#include "StdAfx.h"
#include "xEngineWrite.h"
#include "COLLADAFW.h"
#include "COLLADASaxFWLLoader.h"
#include "xExportVertex.h"
#include "xSceneGraphWrite.h"
#include "OpenColladaHelp.h"
//#include "COLLADAFWRoot.h"
//#include "COLLADAFWGeometry.h"
//#include "COLLADAFWNode.h"
//#include "COLLADAFWVisualScene.h"
//#include "COLLADAFWInstanceGeometry.h"



namespace XE
{

	xEngineWrite::xEngineWrite(const xString& filename,xSceneManager* pSceneManager)
		:m_FileName(filename.c_str()),m_pSceneManager(pSceneManager),mVisualScene(NULL),
		mCurrentRun(SCENEGRAPH_RUN)
	{

	}

	xEngineWrite::~xEngineWrite(void)
	{
	}

	bool xEngineWrite::write()
	{

		COLLADASaxFWL::Loader loader;
		COLLADAFW::Root root(&loader, this);

		// Load scene graph 
		if ( !root.loadDocument(m_FileName.c_str()))
			return false;

		// if there is no visual scene in the COLLADA file, nothing to export here
		if ( mVisualScene )
		{
			SceneGraphWriter sceneGraphWriter(this, *mVisualScene, mLibrayNodesList,m_pSceneManager);
			sceneGraphWriter.write();
		}

		// load and write geometries
		mCurrentRun = GEOMETRY_RUN;
		if ( !root.loadDocument(m_FileName.c_str()) )
			return false;


		BulidScene();
		return true;

	}



	void xEngineWrite::cancel(const xString& errorMessage)
	{
		return ;
	}

	/** This is the method called. The writer hast to prepare to receive data.*/
	void xEngineWrite::start()
	{
		return ;
	}

	/** This method is called after the last write* method. No other methods will be called after this.*/
	void xEngineWrite::finish()
	{
		return;
	}

	/** When this method is called, the writer must write the global document asset.
	@return The writer should return true, if writing succeeded, false otherwise.*/
	bool xEngineWrite::writeGlobalAsset ( const COLLADAFW::FileInfo* asset )
	{
		return true;
	}

	/** When this method is called, the writer must write the scene.
	@return The writer should return true, if writing succeeded, false otherwise.*/
	bool xEngineWrite::writeScene ( const COLLADAFW::Scene* scene )
	{
		return true;
	}
	/** When this method is called, the writer must write the entire visual scene.
	@return The writer should return true, if writing succeeded, false otherwise.*/
	bool xEngineWrite::writeVisualScene ( const COLLADAFW::VisualScene* visualScene )
	{
		if ( mCurrentRun != SCENEGRAPH_RUN )
			return true;
		// todo. handle multiple occurences of visual scene properly. This is just a quick fix
		if ( mVisualScene )
		{
			delete mVisualScene;
		}
		mVisualScene = new COLLADAFW::VisualScene(*visualScene);
		return true;

	}

	/** When this method is called, the writer must handle all nodes contained in the 
	library nodes.
	@return The writer should return true, if writing succeeded, false otherwise.*/
	bool xEngineWrite:: writeLibraryNodes ( const COLLADAFW::LibraryNodes* libraryNodes )
	{
		if ( mCurrentRun != SCENEGRAPH_RUN )
			return true;
		mLibrayNodesList.push_back(*libraryNodes);
		return true;
	}
	/** When this method is called, the writer must write the geometry.
	@return The writer should return true, if writing succeeded, false otherwise.*/
	bool xEngineWrite::writeGeometry ( const COLLADAFW::Geometry* pgeometry )
	{
		if ( mCurrentRun != GEOMETRY_RUN )
			return true;
		if ( pgeometry->getType() != COLLADAFW::Geometry::GEO_TYPE_MESH )
			return true;


		COLLADAFW::Geometry* geometry=(COLLADAFW::Geometry*)pgeometry;
		COLLADAFW::Geometry::GeometryType GeomeType =    geometry->getType();
		if(GeomeType!=COLLADAFW::Geometry::GEO_TYPE_MESH)
			return false;
		COLLADAFW::Mesh* pColladaMesh = static_cast<COLLADAFW::Mesh*>(geometry);

		xMeshWrite meshwrite(this,m_pSceneManager,pColladaMesh);
		return  meshwrite.write();
	}
	/** When this method is called, the writer must write the material.
	@return The writer should return true, if writing succeeded, false otherwise.*/
	bool xEngineWrite::writeMaterial( const COLLADAFW::Material* material )
	{
		if ( mCurrentRun != SCENEGRAPH_RUN )
			return true;
		mUniqueIdFWMaterialMap.insert(std::make_pair(material->getUniqueId(),*material ));
		return true;
	}

	/** When this method is called, the writer must write the effect.
	@return The writer should return true, if writing succeeded, false otherwise.*/
	bool xEngineWrite::writeEffect( const COLLADAFW::Effect* effect )
	{
		if ( mCurrentRun != SCENEGRAPH_RUN )
			return true;
		mUniqueIdFWEffectMap.insert(std::make_pair(effect->getUniqueId(),*effect ));
		return true;
	}

	/** When this method is called, the writer must write the camera.
	@return The writer should return true, if writing succeeded, false otherwise.*/
	bool xEngineWrite::writeCamera( const COLLADAFW::Camera* camera )
	{
		if ( mCurrentRun != SCENEGRAPH_RUN )
			return true;
		return true;
	}

	/** When this method is called, the writer must write the image.
	@return The writer should return true, if writing succeeded, false otherwise.*/
	bool xEngineWrite::writeImage( const COLLADAFW::Image* image ) 
	{
		if ( mCurrentRun != SCENEGRAPH_RUN )
			return true;
		mUniqueIdFWImageMap.insert(std::make_pair(image->getUniqueId(),*image ));
		return true;
	}
	/** When this method is called, the writer must write the light.
	@return The writer should return true, if writing succeeded, false otherwise.*/
	bool xEngineWrite::writeLight( const COLLADAFW::Light* light ) 
	{
		if ( mCurrentRun != SCENEGRAPH_RUN )
			return true;
		return true;
	}

	/** When this method is called, the writer must write the Animation.
	@return The writer should return true, if writing succeeded, false otherwise.*/
	bool xEngineWrite::writeAnimation( const COLLADAFW::Animation* animation )
	{
		return true;
	}

	/** When this method is called, the writer must write the AnimationList.
	@return The writer should return true, if writing succeeded, false otherwise.*/
	bool xEngineWrite::writeAnimationList( const COLLADAFW::AnimationList* animationList )
	{
		return true;
	}

	/** When this method is called, the writer must write the skin controller data.
	@return The writer should return true, if writing succeeded, false otherwise.*/
	bool xEngineWrite::writeSkinControllerData( const COLLADAFW::SkinControllerData* skinControllerData ) 
	{
		return true;
	}

	/** When this method is called, the writer must write the controller.
	@return The writer should return true, if writing succeeded, false otherwise.*/
	bool xEngineWrite::writeController( const COLLADAFW::Controller* controller ) 
	{
		return true;
	}

	/** When this method is called, the writer must write the formulas. All the formulas of the entire
	COLLADA file are contained in @a formulas.
	@return The writer should return true, if writing succeeded, false otherwise.*/
	bool xEngineWrite::writeFormulas( const COLLADAFW::Formulas* formulas ) 
	{
		return true;
	}

	/** When this method is called, the writer must write the kinematics scene. 
	@return The writer should return true, if writing succeeded, false otherwise.*/
	bool xEngineWrite::writeKinematicsScene( const COLLADAFW::KinematicsScene* kinematicsScene )
	{
		return true;
	}


	bool  xEngineWrite::BulidScene()
	{

		GeometryUniqueIdInstanceGeometryInfoMap::iterator it = mGeometryUniqueIdInstanceGeometryInfoMap.begin();
		for(;it!=mGeometryUniqueIdInstanceGeometryInfoMap.end();++it)
		{


			InstanceGeometryInfo& pInstace = it->second;
			COLLADABU::Math::Matrix4 worldMatrix = it->second.worldMatrix;
			xString nodeName =it->second.m_Name;
			xSceneNode* pNode = m_pSceneManager->GetSceneNodeByName(nodeName);

			COLLADAFW::UniqueId Meshid =   pInstace.fwInstanceGeometry->getInstanciatedObjectId();
			UniqueIdMeshMap::iterator MeshIt = mUniqueIdMeshMap.find(Meshid);
			if(MeshIt!=mUniqueIdMeshMap.end())
			{
				xMesh* pMesh = MeshIt->second;
				xString MeshName = pMesh->GetName();

				xEntity3D* pEnt = m_pSceneManager->CreateEntity(nodeName,MeshName);
				if(pNode!=NULL&&pEnt!=NULL)
				{
					pNode->AttachRenderObject(pEnt);
				}

				if(pEnt!=NULL)
				{
					COLLADAFW::MaterialBindingArray& materialArray = pInstace.fwInstanceGeometry->getMaterialBindings();
					size_t materialCount =  materialArray.getCount();
					for(size_t j = 0;j<materialCount;++j)
					{
						COLLADAFW::MaterialBinding MaterialBind =  materialArray[j];
						xString TemName =   MaterialBind.getName();
						UniqueIdFWMaterialMap::iterator matit=  mUniqueIdFWMaterialMap.find(MaterialBind.getReferencedMaterial());
						if(matit!=mUniqueIdFWMaterialMap.end())
						{
							COLLADAFW::Material& InstantMat =  matit->second;
							xString matname =  InstantMat.getName();
							pEnt->SetMaterial(j,matname);

						}

					}

				}




			}

		}
		return true;
	}


}